#!/bin/bash

# ===========================================
# Redis 8.2 一键安装脚本
# 文件名 install-redis-8.2.sh
# 适用于阿里云宝塔Linux系统
# 作者：无畏侠
# 版本：2.2
# 修改记录：
# v1.0 - 初始版本
# v2.0 - 修复systemd服务启动失败问题
#        - 修复daemonize配置问题
#        - 优化systemd服务配置
#        - 增强错误处理和诊断功能
# v2.1 - 修复日志文件权限问题
#        - 确保日志目录和文件可写入
#        - 修复目录创建和权限设置
# v2.2 - 修复重复目录创建导致的权限冲突
#        - 统一目录创建逻辑，避免权限设置冲突
# ===========================================

# 设置脚本参数
REDIS_VERSION="8.2.0"
REDIS_PASSWORD="Hlj@20220715"
REDIS_PORT="6379"
INSTALL_DIR="/usr/local/redis"
CONFIG_DIR="/etc/redis"
DATA_DIR="/var/lib/redis"
LOG_DIR="/var/log/redis"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_step() {
    echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

# 检查是否以root用户运行
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "此脚本必须以root权限运行"
        exit 1
    fi
}

# 检测操作系统
detect_os() {
    if [ -f /etc/redhat-release ]; then
        OS="centos"
    elif [ -f /etc/lsb-release ]; then
        OS="ubuntu"
    elif [ -f /etc/debian_version ]; then
        OS="debian"
    else
        log_error "不支持的操作系统"
        exit 1
    fi
    log_info "检测到操作系统: $OS"
}

# 安装依赖包
install_dependencies() {
    log_step "安装依赖包..."
    
    case $OS in
        "centos")
            yum update -y
            yum install -y gcc gcc-c++ make tcl wget
            ;;
        "ubuntu"|"debian")
            apt-get update
            apt-get install -y build-essential tcl wget
            ;;
    esac
    
    if [ $? -eq 0 ]; then
        log_info "依赖包安装成功"
    else
        log_error "依赖包安装失败"
        exit 1
    fi
}

# 检查并卸载旧版本Redis
check_and_remove_old_redis() {
    log_step "检查并卸载旧版本Redis..."
    
    # 检查Redis是否在运行
    if systemctl is-active --quiet redis; then
        log_info "停止Redis服务..."
        systemctl stop redis
    fi
    
    if pgrep redis-server > /dev/null; then
        log_info "强制停止Redis进程..."
        pkill redis-server
        sleep 2
    fi
    
    # 卸载Redis包
    case $OS in
        "centos")
            if rpm -qa | grep -q redis; then
                log_info "卸载Redis包..."
                yum remove -y redis
            fi
            ;;
        "ubuntu"|"debian")
            if dpkg -l | grep -q redis; then
                log_info "卸载Redis包..."
                apt-get remove -y redis-server
                apt-get autoremove -y
            fi
            ;;
    esac
    
    # 清理残留文件
    log_info "清理残留文件..."
    rm -rf /etc/redis
    rm -rf /var/lib/redis
    rm -rf /var/log/redis
    rm -rf /usr/local/redis
    rm -f /usr/bin/redis-*
    rm -f /usr/local/bin/redis-*
    
    log_info "旧版本Redis清理完成"
}

# 下载并编译Redis
download_and_compile_redis() {
    log_step "下载并编译Redis ${REDIS_VERSION}..."
    
    cd /tmp
    
    # 下载Redis源码
    if [ ! -f "redis-${REDIS_VERSION}.tar.gz" ]; then
        log_info "下载Redis源码包..."
        wget https://download.redis.io/releases/redis-${REDIS_VERSION}.tar.gz
        if [ $? -ne 0 ]; then
            log_error "下载Redis源码失败"
            exit 1
        fi
    fi
    
    # 解压源码
    log_info "解压源码包..."
    tar -xzf redis-${REDIS_VERSION}.tar.gz
    cd redis-${REDIS_VERSION}
    
    # 编译安装
    log_info "编译Redis..."
    make -j$(nproc)
    
    if [ $? -eq 0 ]; then
        log_info "编译成功，开始安装..."
        make install
    else
        log_error "编译失败"
        exit 1
    fi
    
    log_info "Redis编译安装完成"
}

# 创建系统用户和目录
create_system_directories() {
    log_step "创建系统用户和目录..."
    
    # 创建Redis用户
    if ! id redis &>/dev/null; then
        log_info "创建Redis用户..."
        useradd -r -s /bin/false redis
    fi
    
    # 创建目录
    mkdir -p $CONFIG_DIR
    mkdir -p $DATA_DIR
    mkdir -p $LOG_DIR
    mkdir -p /var/run/redis
    
    # 设置目录权限 - 确保redis用户有完全权限
    chown -R redis:redis $CONFIG_DIR
    chown -R redis:redis $DATA_DIR
    chown -R redis:redis $LOG_DIR
    chown -R redis:redis /var/run/redis
    
    # 设置目录权限为755，确保redis用户可以读写
    chmod 755 $CONFIG_DIR
    chmod 755 $DATA_DIR
    chmod 755 $LOG_DIR
    chmod 755 /var/run/redis
    
    # 预创建日志文件并设置权限
    touch $LOG_DIR/redis-server.log
    chown redis:redis $LOG_DIR/redis-server.log
    chmod 644 $LOG_DIR/redis-server.log
    
    log_info "系统目录创建完成"
}

# 配置Redis
configure_redis() {
    log_step "配置Redis..."
    
    cd /tmp/redis-${REDIS_VERSION}
    
    # 复制配置文件
    cp redis.conf $CONFIG_DIR/redis.conf
    cp redis.conf $CONFIG_DIR/redis.conf.backup
    
    # 修改配置文件
    log_info "修改Redis配置文件..."
    
    # 使用sed命令修改配置 - 关键修复：daemonize必须为no，systemd会管理进程
    sed -i 's/^bind 127.0.0.1/# bind 127.0.0.1/' $CONFIG_DIR/redis.conf
    sed -i '/^# bind 127.0.0.1/a bind 0.0.0.0' $CONFIG_DIR/redis.conf
    sed -i 's/^protected-mode yes/protected-mode no/' $CONFIG_DIR/redis.conf
    sed -i "s/^# requirepass foobared/requirepass $REDIS_PASSWORD/" $CONFIG_DIR/redis.conf
    sed -i 's/^daemonize no/daemonize no/' $CONFIG_DIR/redis.conf  # 修复：必须为no
    sed -i "s|^logfile .*|logfile $LOG_DIR/redis-server.log|" $CONFIG_DIR/redis.conf
    sed -i "s|^dir .*|dir $DATA_DIR|" $CONFIG_DIR/redis.conf
    sed -i 's/^# maxmemory <bytes>/maxmemory 512mb/' $CONFIG_DIR/redis.conf
    sed -i 's/^# maxmemory-policy noeviction/maxmemory-policy allkeys-lru/' $CONFIG_DIR/redis.conf
    sed -i 's/^appendonly no/appendonly yes/' $CONFIG_DIR/redis.conf
    
    # 添加systemd兼容性配置
    sed -i 's/^# supervised no/supervised systemd/' $CONFIG_DIR/redis.conf
    sed -i 's/^pidfile .*/pidfile \/var\/run\/redis\/redis-server.pid/' $CONFIG_DIR/redis.conf
    
    # 设置配置文件权限
    chown redis:redis $CONFIG_DIR/redis.conf
    chmod 640 $CONFIG_DIR/redis.conf
    
    log_info "Redis配置完成"
}

# 创建systemd服务文件
create_systemd_service() {
    log_step "创建systemd服务文件..."
    
    # 创建PID文件目录
    mkdir -p /var/run/redis
    chown redis:redis /var/run/redis
    
    cat > /etc/systemd/system/redis.service << EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
Documentation=https://redis.io/documentation

[Service]
Type=notify
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf --supervised systemd
ExecReload=/bin/kill -USR2 \$MAINPID
TimeoutStopSec=5
Restart=on-failure
RestartSec=5
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755

# 安全设置
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectHome=yes
ReadWritePaths=/var/lib/redis /var/log/redis /var/run/redis

# 资源限制
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
    
    # 重新加载systemd
    systemctl daemon-reload
    
    log_info "systemd服务文件创建完成"
}

# 配置防火墙
configure_firewall() {
    log_step "配置防火墙..."
    
    case $OS in
        "centos")
            if systemctl is-active --quiet firewalld; then
                log_info "配置firewalld..."
                firewall-cmd --permanent --add-port=${REDIS_PORT}/tcp
                firewall-cmd --reload
            fi
            ;;
        "ubuntu"|"debian")
            if command -v ufw > /dev/null && ufw status | grep -q "Status: active"; then
                log_info "配置ufw..."
                ufw allow ${REDIS_PORT}/tcp
                ufw reload
            fi
            ;;
    esac
    
    log_info "防火墙配置完成"
}

# 启动Redis服务
start_redis_service() {
    log_step "启动Redis服务..."
    
    # 确保目录权限正确 - 不再重复创建，只验证权限
    log_info "验证目录权限..."
    if [ ! -d "$DATA_DIR" ]; then
        mkdir -p $DATA_DIR
        chown redis:redis $DATA_DIR
        chmod 755 $DATA_DIR
    fi
    
    if [ ! -d "$LOG_DIR" ]; then
        mkdir -p $LOG_DIR
        chown redis:redis $LOG_DIR
        chmod 755 $LOG_DIR
    fi
    
    if [ ! -d "/var/run/redis" ]; then
        mkdir -p /var/run/redis
        chown redis:redis /var/run/redis
        chmod 755 /var/run/redis
    fi
    
    # 确保日志文件存在且权限正确
    if [ ! -f "$LOG_DIR/redis-server.log" ]; then
        touch $LOG_DIR/redis-server.log
        chown redis:redis $LOG_DIR/redis-server.log
        chmod 644 $LOG_DIR/redis-server.log
    fi
    
    # 检查配置文件语法
    log_info "检查Redis配置文件语法..."
    if ! /usr/local/bin/redis-server /etc/redis/redis.conf --test-memory 1 > /dev/null 2>&1; then
        log_warn "配置文件语法检查失败，但继续尝试启动..."
    fi
    
    # 启动服务
    systemctl start redis
    systemctl enable redis
    
    # 等待服务启动，增加重试机制
    log_info "等待Redis服务启动..."
    for i in {1..10}; do
        if systemctl is-active --quiet redis; then
            log_info "Redis服务启动成功"
            break
        elif [ $i -eq 10 ]; then
            log_error "Redis服务启动失败"
            log_info "检查服务状态和日志..."
            systemctl status redis
            journalctl -u redis --no-pager -n 20
            
            # 尝试手动启动调试
            log_info "尝试手动启动调试..."
            sudo -u redis /usr/local/bin/redis-server /etc/redis/redis.conf --daemonize no &
            sleep 2
            if pgrep redis-server > /dev/null; then
                log_info "手动启动成功，检查配置问题"
                pkill redis-server
            fi
            exit 1
        else
            sleep 2
        fi
    done
}

# 验证安装
verify_installation() {
    log_step "验证安装..."
    
    # 测试本地连接
    log_info "测试本地连接..."
    if redis-cli -a "$REDIS_PASSWORD" ping | grep -q "PONG"; then
        log_info "本地连接测试成功"
    else
        log_error "本地连接测试失败"
        exit 1
    fi
    
    # 测试基本操作
    log_info "测试基本操作..."
    redis-cli -a "$REDIS_PASSWORD" set "test_key" "test_value" > /dev/null
    if redis-cli -a "$REDIS_PASSWORD" get "test_key" | grep -q "test_value"; then
        log_info "基本操作测试成功"
        # 清理测试数据
        redis-cli -a "$REDIS_PASSWORD" del "test_key" > /dev/null
    else
        log_error "基本操作测试失败"
        exit 1
    fi
    
    # 显示安装信息
    log_info "显示Redis信息..."
    redis-cli -a "$REDIS_PASSWORD" info server | grep -E "(redis_version|redis_mode|os|arch_bits|process_id|tcp_port)"
}

# 显示安装摘要
show_installation_summary() {
    log_step "=== 安装完成 ==="
    echo -e "${GREEN}Redis ${REDIS_VERSION} 安装配置完成${NC}"
    echo ""
    echo -e "${BLUE}安装信息摘要:${NC}"
    echo "=============================="
    echo -e "Redis版本: ${GREEN}${REDIS_VERSION}${NC}"
    echo -e "服务端口: ${GREEN}${REDIS_PORT}${NC}"
    echo -e "连接密码: ${GREEN}${REDIS_PASSWORD}${NC}"
    echo -e "配置文件: ${GREEN}${CONFIG_DIR}/redis.conf${NC}"
    echo -e "数据目录: ${GREEN}${DATA_DIR}${NC}"
    echo -e "日志文件: ${GREEN}${LOG_DIR}/redis-server.log${NC}"
    echo ""
    echo -e "${BLUE}服务管理命令:${NC}"
    echo "=============================="
    echo "启动服务: systemctl start redis"
    echo "停止服务: systemctl stop redis"
    echo "重启服务: systemctl restart redis"
    echo "查看状态: systemctl status redis"
    echo "查看日志: tail -f ${LOG_DIR}/redis-server.log"
    echo ""
    echo -e "${BLUE}客户端连接:${NC}"
    echo "=============================="
    echo "本地连接: redis-cli -a ${REDIS_PASSWORD}"
    echo "远程连接: redis-cli -h 服务器IP -p ${REDIS_PORT} -a ${REDIS_PASSWORD}"
    echo ""
    echo -e "${YELLOW}安全提醒:${NC}"
    echo "=============================="
    echo "1. 请确保防火墙已正确配置"
    echo "2. 定期备份重要数据"
    echo "3. 监控内存使用情况"
    echo "4. 定期更换密码"
    echo ""
}

# 主函数
main() {
    echo -e "${GREEN}===========================================${NC}"
    echo -e "${GREEN}    Redis ${REDIS_VERSION} 一键安装脚本    ${NC}"
    echo -e "${GREEN}===========================================${NC}"
    echo ""
    
    # 执行安装步骤
    check_root
    detect_os
    install_dependencies
    check_and_remove_old_redis
    download_and_compile_redis
    create_system_directories
    configure_redis
    create_systemd_service
    configure_firewall
    start_redis_service
    verify_installation
    show_installation_summary
    
    echo -e "${GREEN}安装完成！${NC}"
}

# 执行主函数
main "$@"